//
//  VSImageUtil.m
//
//
//  Created by easelin on 13-11-21.
//  Copyright (c) 2013年 commsupport. All rights reserved.
//

#import <CoreGraphics/CoreGraphics.h>
#import "VSImageUtil.h"

/*
size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef);
size_t bytesPerRow = 0; // CGImageGetBytesPerRow() calculates incorrectly in iOS 5.0, so defer to CGBitmapContextCreate()
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);

if (CGColorSpaceGetNumberOfComponents(colorSpace) == 3) {
    uint32_t alpha = (bitmapInfo & kCGBitmapAlphaInfoMask);
    if (alpha == kCGImageAlphaNone) {
        bitmapInfo &= ~kCGBitmapAlphaInfoMask;
        bitmapInfo |= kCGImageAlphaNoneSkipFirst;
    } else if (!(alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast)) {
        bitmapInfo &= ~kCGBitmapAlphaInfoMask;
        bitmapInfo |= kCGImageAlphaPremultipliedFirst;
    }
}

CGContextRef context = CGBitmapContextCreate(NULL, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);

CGColorSpaceRelease(colorSpace);
*/

/**
 结束一个画布
 */
void VSImageEndImageContext(CGContextRef context)
{
    if (context)
    {
        CGContextRelease(context);
    }
}

/**
 生成一个画布
 */
CGContextRef VSImageBeginImageContext(CGImageRef image, CGFloat scale, CGSize dotSize, CGFloat cornerRadius, VSImageDrawFrameOption option)
{
    // TODO: 暂不考虑方向问题
//    switch ([image imageOrientation]) {
//        case UIImageOrientationLeft:
//        case UIImageOrientationRight:
//        case UIImageOrientationLeftMirrored:
//        case UIImageOrientationRightMirrored:
//            potWidth = dotSize.height * scale;
//            potHeight = dotSize.width * scale;
//            break;
//        default:
//            potWidth = dotSize.width * scale;
//            potHeight = dotSize.height * scale;
//            break;
//    }
    
    CGFloat pxWidth = dotSize.width * scale;
    CGFloat pxHeight = dotSize.height * scale;
    // 计算透明通道
    CGImageAlphaInfo info;
    // 有圆角的情况，必须有透明通道
    if (0 < cornerRadius || VSImageDrawFrameOptionScaleToFillCircle == option)
    {
        info = kCGImageAlphaPremultipliedLast;
    }
    else
    {
        info = CGImageGetAlphaInfo(image);
        //info = kCGImageAlphaPremultipliedLast;  // issue #886. This patch breaks BMP images.
        if (kCGImageAlphaPremultipliedLast == info
            || kCGImageAlphaPremultipliedFirst == info
            || kCGImageAlphaLast == info
            || kCGImageAlphaFirst == info)
        {
            info = kCGImageAlphaPremultipliedLast;
        }
        else
        {
            info = kCGImageAlphaNoneSkipLast;
        }
    }
    CGColorSpaceRef colorSpaceInfo = CGColorSpaceCreateDeviceRGB();
    //CGBitmapContextCreate(data, POTWide, POTHigh, 8, 4 * POTWide, colorSpace, info | kCGBitmapByteOrderDefault);
    CGContextRef ctx = CGBitmapContextCreate(NULL, pxWidth, pxHeight, 8, 0, colorSpaceInfo, (kCGBitmapAlphaInfoMask & info));
    CGColorSpaceRelease(colorSpaceInfo);
    return ctx;
}

/**
 从画布生成一个图片
 */
void VSImageCreateImageFromContext(CGContextRef context, CGFloat scale, CGImageRef *imagePtr)
{
    CGImageRef image = CGBitmapContextCreateImage(context);
    if (image && imagePtr)
    {
        *imagePtr = image;
    }
}

/**
 画一张图片，切记CG开头的坐标轴方向
 */
void VSImageDrawImageInContext(CGContextRef context, CGImageRef image, CGFloat scale, CGRect drawRect, CGFloat cornerRadius, VSImageDrawFrameOption option)
{
    // TODO: 暂不考虑方向问题
//    switch ([image imageOrientation]) {
//        case UIImageOrientationLeft:
//        case UIImageOrientationRight:
//        case UIImageOrientationLeftMirrored:
//        case UIImageOrientationRightMirrored:
//            contextPotWide = contextSize.height * scale;
//            contextPotHigh = contextSize.width * scale;
//            imagePotWide = drawRect.size.height * scale;
//            imagePotHigh = drawRect.size.width * scale;
//            potx = drawRect.origin.y * scale;
//            poty = drawRect.origin.x * scale;
//            break;
//        default:
//            contextPotWide = contextSize.width * scale;
//            contextPotHigh = contextSize.height * scale;
//            imagePotWide = drawRect.size.width * scale;
//            imagePotHigh = drawRect.size.height * scale;
//            potx = drawRect.origin.x * scale;
//            poty = drawRect.origin.y * scale;
//            break;
//    }

    CGFloat drawPxx = 0, drawPxy = 0;
    CGFloat imagePxWidth = CGImageGetWidth(image);
    CGFloat imagePxHeight = CGImageGetHeight(image);
    CGFloat drawPxWidth = drawRect.size.width * scale;
    CGFloat drawPxHeight = drawRect.size.height * scale;
    
    CGPathRef path = NULL;
    if (VSImageDrawFrameOptionScaleToFillCircle != option && 0 < cornerRadius)
    {
#if TARGET_OS_IPHONE
        // 圆角
        path = [[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, drawPxWidth, drawPxHeight) cornerRadius:cornerRadius] CGPath];
#else
#warning "unsupport"
#endif
    }
    else if (VSImageDrawFrameOptionScaleToFillCircle == option)
    {
#if TARGET_OS_IPHONE
        // 圆形
        path = [[UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, drawPxWidth, drawPxHeight)] CGPath];
#else
#warning "unsupport"
#endif
    }
    if (path)
    {
        CGContextAddPath(context, path);
        CGContextClosePath(context);
        CGContextClip(context);
    }
    
    switch (option)
    {
        case VSImageDrawFrameOptionLocateSubFrame:
        {
            // x轴方向NS和CG不变
            drawPxx = - drawRect.origin.x * scale;
            // y轴则相反
            drawPxy = - (imagePxHeight - (drawRect.origin.y + drawRect.size.height) * scale);
            // 画图
            CGContextDrawImage(context, CGRectMake(drawPxx, drawPxy, imagePxWidth, imagePxHeight), image);
        }
            break;
        case VSImageDrawFrameOptionLocateCenter:
        {
            // x轴方向NS和CG不变
            drawPxx = - (imagePxWidth - drawPxWidth) * 0.5f;
            // y轴则相反
            drawPxy = - (imagePxHeight - drawPxHeight) * 0.5f;
            // 画图
            CGContextDrawImage(context, CGRectMake(drawPxx, drawPxy, imagePxWidth, imagePxHeight), image);
        }
            break;
        case VSImageDrawFrameOptionScaleToFillWidth:
        case VSImageDrawFrameOptionScaleToFillHeight:
        case VSImageDrawFrameOptionScaleToFillCircle:
        {
            CGFloat scaledWidth = drawPxWidth;
            CGFloat scaledHeight = drawPxHeight;
            // 长宽比不一样的情况
            if ((drawPxHeight / drawPxWidth) != (imagePxHeight / imagePxWidth))
            {
                CGFloat widthFactor = drawPxWidth / imagePxWidth;
                CGFloat heightFactor = drawPxHeight / imagePxHeight;
                
                BOOL scaleToWidth;
                CGFloat scaleFactor;
                if (VSImageDrawFrameOptionScaleToFillWidth == option)
                {
                    scaleToWidth = YES;
                    scaleFactor = widthFactor;// scale to fit width
                }
                else if (VSImageDrawFrameOptionScaleToFillHeight == option)
                {
                    scaleToWidth = NO;
                    scaleFactor = heightFactor;// scale to fit height
                }
                else
                {
                    if (widthFactor > heightFactor)
                    {
                        scaleToWidth = YES;
                        scaleFactor = widthFactor; // scale to fit width
                    }
                    else
                    {
                        scaleToWidth = NO;
                        scaleFactor = heightFactor; // scale to fit height
                    }
                }
                
                if (scaleToWidth)
                {
                    scaledHeight = imagePxHeight * scaleFactor;
                    drawPxy = (drawPxHeight - scaledHeight) * 0.5f;
                }
                else
                {
                    scaledWidth = imagePxWidth * scaleFactor;
                    drawPxx = (drawPxWidth - scaledWidth) * 0.5f;
                }
            }
            CGContextDrawImage(context, CGRectMake(drawPxx, drawPxy, scaledWidth, scaledHeight), image);
        }
            break;
        case VSImageDrawFrameOptionFillFull:
        {
            CGContextDrawImage(context, CGRectMake(0, 0, drawPxWidth, drawPxHeight), image);
        }
            break;
    }
    
}

CGImageRef VSImageCreateImageOnRect(CGImageRef image, CGFloat scale, CGRect rect, CGFloat cornerRadius, VSImageDrawFrameOption option)
{
    if((image) == NULL || rect.size.width == 0 || rect.size.height == 0)
    {
        return nil;
    }
    
    CGContextRef context = VSImageBeginImageContext(image, scale, rect.size, cornerRadius, option);
    
    if (context)
    {
        CGImageRef aImageRef = NULL;
        VSImageDrawImageInContext(context, image, scale, rect, cornerRadius, option);
        VSImageCreateImageFromContext(context, scale, &aImageRef);
        VSImageEndImageContext(context);
        return aImageRef;
    }
    
    return NULL;
}

#pragma mark - iOS

#if TARGET_OS_IPHONE

UIImage * VSImageGenerateImageOnRect(UIImage *image, CGRect rect, CGFloat cornerRadius, VSImageDrawFrameOption frameOption)
{
    CGFloat scale = [[UIScreen mainScreen] scale];
    CGImageRef imageRef = VSImageCreateImageOnRect([image CGImage], scale, rect, cornerRadius, frameOption);
    if (imageRef)
    {
        UIImage *aImage = [UIImage imageWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
        CGImageRelease(imageRef);
        return aImage;
    }
    return nil;
}
UIImage * VSImageGenerateImageByFixOrientation(UIImage *image) {
    
    // No-op if the orientation is already correct
    if (image.imageOrientation == UIImageOrientationUp)
        return image;
    
    // We need to calculate the proper transformation to make the image upright.
    // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
    CGAffineTransform transform = CGAffineTransformIdentity;
    
    switch (image.imageOrientation) {
        case UIImageOrientationDown:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, image.size.width, image.size.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;
            
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate(transform, image.size.width, 0);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;
            
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, 0, image.size.height);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;
        default:
            break;
    }
    
    switch (image.imageOrientation) {
        case UIImageOrientationUpMirrored:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, image.size.width, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
            
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, image.size.height, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
        default:
            break;
    }
    
    // Now we draw the underlying CGImage into a new context, applying the transform
    // calculated above.
    CGContextRef ctx = CGBitmapContextCreate(NULL, image.size.width, image.size.height,
                                             CGImageGetBitsPerComponent(image.CGImage), 0,
                                             CGImageGetColorSpace(image.CGImage),
                                             CGImageGetBitmapInfo(image.CGImage));
    CGContextConcatCTM(ctx, transform);
    switch (image.imageOrientation) {
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            // Grr...
            CGContextDrawImage(ctx, CGRectMake(0,0,image.size.height,image.size.width), image.CGImage);
            break;
            
        default:
            CGContextDrawImage(ctx, CGRectMake(0,0,image.size.width,image.size.height), image.CGImage);
            break;
    }
    
    // And now we just create a new UIImage from the drawing context
    CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
    UIImage *img = [UIImage imageWithCGImage:cgimg];
    CGContextRelease(ctx);
    CGImageRelease(cgimg);
    return img;
}

//UIImage * VSImageGenerateImageByFixOrientation(UIImage *image)
//{
//    // 假如原来就是竖直方向，直接返回
//    if (UIImageOrientationUp == image.imageOrientation
//        || UIImageOrientationUpMirrored == image.imageOrientation)
//    {
//        return image;
//    }
//    
//    // 假如不是，重新在画板生成
//    CGFloat scale = [image scale];
//    CGSize dotSize = [image size];
//    
//    UIImage *resultImage = nil;
//
//#if 1
//    
//    // 计算画布大小
//    CGFloat pxWidth, pxHeight;
//    switch ([image imageOrientation])
//    {
//        case UIImageOrientationLeft:
//        case UIImageOrientationRight:
//        case UIImageOrientationLeftMirrored:
//        case UIImageOrientationRightMirrored:
//            pxWidth = dotSize.height * scale;
//            pxHeight = dotSize.width * scale;
//            break;
//        default:
//            pxWidth = dotSize.width * scale;
//            pxHeight = dotSize.height * scale;
//            break;
//    }
//    // 计算透明通道
//    CGImageAlphaInfo info;
//    info = CGImageGetAlphaInfo([image CGImage]);
//    //info = kCGImageAlphaPremultipliedLast;  // issue #886. This patch breaks BMP images.
//    if (kCGImageAlphaPremultipliedLast == info
//        || kCGImageAlphaPremultipliedFirst == info
//        || kCGImageAlphaLast == info
//        || kCGImageAlphaFirst == info)
//    {
//        info = kCGImageAlphaPremultipliedLast;
//    }
//    else
//    {
//        info = kCGImageAlphaNoneSkipLast;
//    }
//    CGColorSpaceRef colorSpaceInfo = CGColorSpaceCreateDeviceRGB();
//    // CGBitmapContextCreate(data, POTWide, POTHigh, 8, 4 * POTWide, colorSpace, info | kCGBitmapByteOrderDefault);
//    CGContextRef context = CGBitmapContextCreate(NULL, pxWidth, pxHeight, 8, 0, colorSpaceInfo, (kCGBitmapAlphaInfoMask & info));
//    CGColorSpaceRelease(colorSpaceInfo);
//    
//    CGFloat imagePxWide, imagePxHigh;
//    // 处理方向问题
//    switch ([image imageOrientation])
//    {
//        case UIImageOrientationLeft:
//        case UIImageOrientationRight:
//        case UIImageOrientationLeftMirrored:
//        case UIImageOrientationRightMirrored:
//            imagePxWide = dotSize.height * scale;
//            imagePxHigh = dotSize.width * scale;
//            break;
//        default:
//            imagePxWide = dotSize.width * scale;
//            imagePxHigh = dotSize.height * scale;
//            break;
//    }
//    // 画图片
//    CGContextDrawImage(context, CGRectMake(0, 0, imagePxWide, imagePxHigh), [image CGImage]);
//    
//    CGImageRef imageRef = CGBitmapContextCreateImage(context);
//    
//    if (imageRef)
//    {
//        resultImage = [UIImage imageWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
//        CGImageRelease(imageRef);
//    }
//    
//    CGContextRelease(context);
//    
//#else
//    
//    // 生成画布
//    CGFloat potWidth, potHeight;
//    switch (image.imageOrientation)
//    {
//        case UIImageOrientationLeft:
//        case UIImageOrientationRight:
//        case UIImageOrientationLeftMirrored:
//        case UIImageOrientationRightMirrored:
//            potWidth = dotSize.height;
//            potHeight = dotSize.width;
//            break;
//        default:
//            potWidth = dotSize.width;
//            potHeight = dotSize.height;
//            break;
//    }
//    // Begin a new image that will be the new image with the rounded corners
//    // (here with the size of an UIImageView)
//    UIGraphicsBeginImageContextWithOptions(CGSizeMake(potWidth, potHeight), NO, scale);
//    CGContextRef context = UIGraphicsGetCurrentContext();
//    
//    // We need to calculate the proper transformation to make the image upright.
//    // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
//    CGAffineTransform transform = CGAffineTransformIdentity;
//    switch (image.imageOrientation)
//    {
//        case UIImageOrientationDown:
//        case UIImageOrientationDownMirrored:
//            transform = CGAffineTransformTranslate(transform, dotSize.width, dotSize.height);
//            // transform = CGAffineTransformRotate(transform, M_PI);
//            break;
//        case UIImageOrientationLeft:
//        case UIImageOrientationLeftMirrored:
//            transform = CGAffineTransformTranslate(transform, dotSize.width, 0);
//            transform = CGAffineTransformRotate(transform, M_PI_2);
//            break;
//            
//        case UIImageOrientationRight:
//        case UIImageOrientationRightMirrored:
//            transform = CGAffineTransformTranslate(transform, 0, dotSize.width);
//            transform = CGAffineTransformRotate(transform, -M_PI_2);
//            break;
//        case UIImageOrientationUp:
//        case UIImageOrientationUpMirrored:
//            break;
//    }
//    switch (image.imageOrientation)
//    {
//        case UIImageOrientationUpMirrored:
//        case UIImageOrientationDownMirrored:
//            transform = CGAffineTransformTranslate(transform, dotSize.width, 0);
//            transform = CGAffineTransformScale(transform, -1, 1);
//            break;
//            
//        case UIImageOrientationLeftMirrored:
//        case UIImageOrientationRightMirrored:
//            transform = CGAffineTransformTranslate(transform, dotSize.height, 0);
//            transform = CGAffineTransformScale(transform, -1, 1);
//            break;
//        case UIImageOrientationUp:
//        case UIImageOrientationDown:
//        case UIImageOrientationLeft:
//        case UIImageOrientationRight:
//            break;
//    }
//    // 变换矩阵
//    CGContextConcatCTM(context, transform);
//    
//    // Draw your image
//    [image drawInRect:CGRectMake(0, 0, dotSize.width, dotSize.height)];
//    
//    //TODO: could not set orientation
//    resultImage = UIGraphicsGetImageFromCurrentImageContext();
//    
//    // Lets forget about that we were drawing
//    UIGraphicsEndImageContext();
//    
//#endif
//    
//    return resultImage;
//}

#endif
